package avicit.bdp.lineage.druid.process.statement;

import avicit.bdp.lineage.druid.contants.ParserConstant;
import avicit.bdp.lineage.druid.model.ColumnNode;
import avicit.bdp.lineage.druid.model.TableNode;
import avicit.bdp.lineage.druid.model.TreeNode;
import avicit.bdp.lineage.druid.process.ProcessorRegister;
import avicit.bdp.lineage.druid.process.SqlExprContent;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import com.alibaba.druid.sql.ast.statement.SQLWithSubqueryClause;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * <p>
 * AbstractStatement
 * </p>
 *
 */
public abstract class AbstractStatementProcessor implements StatementProcessor {

    @Override
    public void process(String dbType, AtomicInteger sequence, TreeNode<TableNode> root, SQLStatement statement) {
        this.doProcess(dbType, sequence, root, statement);
        this.after(dbType, sequence, root, statement);
    }

    protected void doProcess(String dbType, AtomicInteger sequence, TreeNode<TableNode> root, SQLStatement statement) {
    }

    protected void constructRootNode(String dbType, TreeNode<TableNode> root, SQLStatement statement,
                                     SQLExprTableSource sqlExprTableSource) {
        SQLExpr sqlExpr = sqlExprTableSource.getExpr();
        SqlExprContent content = new SqlExprContent();
        ProcessorRegister.getSQLExprProcessor(sqlExpr.getClass()).process(dbType, sqlExpr, content);
        String tableName = content.getName();
        String schemaName = content.getOwner();
        TableNode tableNode = TableNode.builder()
                .isVirtualTemp(false)
                .schemaName(schemaName)
                .name(tableName)
                .build();
        root.setValue(tableNode);
        try {
            tableNode.setExpression(SQLUtils.toSQLString(statement));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void constructRootNodeField(String dbType, TreeNode<TableNode> root, SQLStatement statement,
                                          List<SQLExpr> exprList) {
        TableNode tableNode = root.getValue();
        for (SQLExpr sqlExpr : exprList) {
            SqlExprContent content = new SqlExprContent();
            ProcessorRegister.getSQLExprProcessor(sqlExpr.getClass()).process(dbType, sqlExpr, content);
            String name = content.getName();
            String tableName = content.getOwner();
            if (StringUtils.isBlank(tableName)) {
                tableName = tableNode.getName();
            }
            ColumnNode columnNode = ColumnNode.builder().name(name).owner(tableNode).tableName(tableName).tableSchemaName(tableNode.getSchemaName()).build();
            root.getValue().getColumns().add(columnNode);
        }

    }

    public void processWithSQL(String dbType, AtomicInteger sequence, TreeNode<TableNode> parent,
                               SQLWithSubqueryClause sqlWithSubqueryClause) {
        List<SQLWithSubqueryClause.Entry> list = sqlWithSubqueryClause.getEntries();
        for (SQLWithSubqueryClause.Entry entry : list) {
            // 执行SQLSelectQuery 查询
            SQLSelectQuery sqlSelectQuery = entry.getSubQuery().getQuery();

            // 建立中间表节点
            TableNode proxyTable = TableNode.builder()
                    .isVirtualTemp(true)
                    .expression(SQLUtils.toSQLString(sqlWithSubqueryClause))
                    .name(ParserConstant.TEMP_TABLE_PREFIX + sequence.incrementAndGet())
                    .alias(entry.getAlias())
                    .build();
            TreeNode<TableNode> proxyNode = TreeNode.of(proxyTable);
            parent.addChild(proxyNode);

            ProcessorRegister.getSQLSelectQueryProcessor(sqlSelectQuery.getClass())
                    .process(dbType, sequence, proxyNode, sqlSelectQuery);
        }
    }


    protected void after(String dbType, AtomicInteger sequence, TreeNode<TableNode> root, SQLStatement statement) {
        //  处理完之后的操作
        //  合并Union
    }
}
